package com.jml.spring.MVC.servlet;

import com.jml.spring.MVC.annotation.ExtController;
import com.jml.spring.MVC.annotation.ExtRequestMapping;
import com.jml.spring.MVC.annotation.反射工具类.ClassUtil;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;

//自定义前端控制器
public class ExtDispatcherServlet  extends HttpServlet {
	//springmvc容器对象  key为首字母小写类名，value是Extcontroller实体类
	private ConcurrentHashMap<String , Object> springmvcBeans = new ConcurrentHashMap<String , Object>();
	//请求地址，key为映射，value是Extcontroller实体类
	private ConcurrentHashMap<String , Object> urlBeans = new ConcurrentHashMap<String , Object>();
	//方法名字   key为映射，value是方法名字
	private ConcurrentHashMap<String , String> urlMethods = new ConcurrentHashMap<String , String>();
	//正常应该你这个  key为映射 value是方法信息(里面的key是方法名字，value是参数类型。)
	//private ConcurrentHashMap<String , ConcurrentHashMap<String , List>> urlMethods = new ConcurrentHashMap<String , String>();

	@Override
	public void init() throws ServletException {
		//1.获取当前包下所有的类
		List<Class<?>> classes = ClassUtil.getClasses("com.jml.spring.MVC.controller");
		//2.扫包判断类上是否有注解ExtController
		try {
			findClassExitAnnotation(classes);
		}catch (Exception e) {
			e.printStackTrace();
		}
		//3.将url和方法映射关联
		handlerMapping();
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//1.获取请求url地址
		String requestURI = req.getRequestURI();
		//2.从map集合中获取控制对象
		Object object = urlBeans.get(requestURI);
		if(object==null){
			resp.getWriter().println("404  404  404  404  not found url");
			return;
		}
		//3.使用url地址获取方法
		String methodName = urlMethods.get(requestURI);
		if(StringUtils.isEmpty(methodName)){
			resp.getWriter().println("404  404  404  404  not found method");
		}
		//4.使用java的反射机制调用方法
		//这里默认返回值是String类型了，真正的mvc是需要判断类型，根据类型决定是返回页面还是json
		String resultPage = (String)methodInvoke(object, methodName);
		//5.使用java的反射获取方法返回结果，类型

		//6.调用视图转换器，渲染给页面展示
		resourcesViewResolver(resultPage,req,resp);
		resp.getWriter().println(resultPage);
	}

	private void resourcesViewResolver(String pageName,HttpServletRequest req,HttpServletResponse resp)
			throws ServletException, IOException {
		//根路径
		String prefix="/";
		String suffix = ".jsp";

		req.getRequestDispatcher(prefix+pageName+suffix).forward(req,resp);
	}

	private Object methodInvoke(Object object ,String methodName){
		try {
			Class<?> classInfo = object.getClass();
			Method method = classInfo.getMethod(methodName);
			Object result = method.invoke(object);
			return result;
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	//2.扫包判断类上是否有注解ExtController,有就实例化放入map中key默认类名小写value是带有ExtController注解的对象
	public void findClassExitAnnotation(List<Class<?>> classes)throws  Exception {
		for (Class<?> classInfo: classes) {
			ExtController extController = classInfo.getAnnotation(ExtController.class);
			if(extController!=null){
				//key默认类名小写
				String simpleName = classInfo.getSimpleName();
				String className = toLowerCaseFirstOne(simpleName);
				//value是带有ExtController注解的对象
				Object object = classInfo.newInstance();
				springmvcBeans.put(className,object);
			}
		}

	}

	//首字母转小写
	public static String toLowerCaseFirstOne(String s) {
		if (Character.isLowerCase(s.charAt(0)))
			return s;
		else
			return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
	}

	//3.将url和方法映射关联
	public void handlerMapping(){
		//获取springmvc的bean容器对象,遍历springmvc的bean容器
		for (Map.Entry<String,Object> mvcBean:springmvcBeans.entrySet()) {
			Object object = mvcBean.getValue();
			Class<?> classInfo = object.getClass();
			ExtRequestMapping declaredAnnotation = classInfo.getDeclaredAnnotation(ExtRequestMapping.class);
			//判断类上是否有@ExtRequestMapping注解
			String baseUrl = "";
			if(declaredAnnotation!=null){
				baseUrl = declaredAnnotation.value();
			}
			//判断方法上是否有@ExtRequestMapping注解
			Method[] declaredMethods = classInfo.getDeclaredMethods();
			for (Method method: declaredMethods) {
				ExtRequestMapping extRequestMapping = method.getDeclaredAnnotation(ExtRequestMapping.class);
				if(extRequestMapping!=null){
					String methodUrl = baseUrl + extRequestMapping.value();
					//装载容器
					//请求地址，key为映射，value是Extcontroller实体类
					urlBeans.put(methodUrl,object);
					//方法名字   key为映射，value是方法名字
					urlMethods.put(methodUrl,method.getName());
				}
			}
		}
	}
}
